#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QInputDialog>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkCellArray.h>
#include <vtkPolyLine.h>
#include <QInputDialog>
#include <QMessageBox>
#include <QDebug>
#include <QDoubleValidator>
#include <QVBoxLayout>
#include <vtkSTLReader.h>
#include <QFileDialog>
#include <vtkImplicitPolyDataDistance.h>
#include <vtkCellLocator.h>
#include <vtkDijkstraGraphGeodesicPath.h>
#include <vtkPointLocator.h>
#include <vtkMath.h>
#include <vtkCellPicker.h>
#include <Eigen/Dense>
#include <vtkObject.h>
#include <vtkCallbackCommand.h>

#include <vtkKdTreePointLocator.h>

#include <CL/cl.h>
#include <fstream>
#include <string>
#include <QtCore>
#include <CL/cl.hpp>
#include <stdexcept>



std::vector<double> MainWindow::PointOntoSurface(
    std::vector<double> point,
    vtkSmartPointer<vtkPolyData> polyData)
{
    vtkSmartPointer<vtkImplicitPolyDataDistance> distanceFunction = vtkSmartPointer<vtkImplicitPolyDataDistance>::New();
    distanceFunction->SetInput(polyData);

    vtkSmartPointer<vtkCellLocator> locator = vtkSmartPointer<vtkCellLocator>::New();
    locator->SetDataSet(polyData);
    locator->BuildLocator();

    double closestPoint[3];  // 最近点坐标
    vtkIdType cellId;
    int subId;
    double dist2;
    locator->FindClosestPoint(point.data(), closestPoint, cellId, subId, dist2);

    return {closestPoint[0], closestPoint[1], closestPoint[2]};
}



vtkSmartPointer<vtkPolyData> GetGeodesicPath(
    vtkPolyData* mesh,
    const double startPoint[3],
    const double endPoint[3])
{
    // 创建定位器找到最近的顶点
    vtkSmartPointer<vtkKdTreePointLocator> pointLocator = vtkSmartPointer<vtkKdTreePointLocator>::New();
    pointLocator->SetDataSet(mesh);
    pointLocator->BuildLocator();


    vtkIdType startId = pointLocator->FindClosestPoint(startPoint);
    vtkIdType endId = pointLocator->FindClosestPoint(endPoint);

    // 计算测地路径
    vtkSmartPointer<vtkDijkstraGraphGeodesicPath> dijkstra =vtkSmartPointer<vtkDijkstraGraphGeodesicPath>::New();
    dijkstra->SetInputData(mesh);
    dijkstra->SetStartVertex(startId);
    dijkstra->SetEndVertex(endId);
    dijkstra->Update();

    // qDebug() << "5";

    return dijkstra->GetOutput();
}



std::vector<double> MainWindow::GeodesicInterpolation(
    vtkPolyData* mesh,
    const std::vector<double>& startPoint,
    const std::vector<double>& endPoint,
    double t)
{
    //qDebug() << " 计算总测地线长度";
    MainWindow mainWindow;


    // 计算总测地长度
    vtkSmartPointer<vtkPolyData> path=GetGeodesicPath(mesh, startPoint.data(), endPoint.data());
    double totalLength = 0.0;
    vtkPoints* points = path->GetPoints();

    for (int i = 0; i < points->GetNumberOfPoints()-1; i++) {
        double p1[3], p2[3];
        points->GetPoint(i, p1);
        points->GetPoint(i+1, p2);
        totalLength += sqrt(vtkMath::Distance2BetweenPoints(p1, p2));
    }

    // 找到目标比例点
    double targetLength = t * totalLength;
    double accumulatedLength = 0.0;
    for (int i = 0; i < points->GetNumberOfPoints()-1; i++) {
        double p1[3], p2[3];
        points->GetPoint(i, p1);
        points->GetPoint(i+1, p2);
        double segmentLength = sqrt(vtkMath::Distance2BetweenPoints(p1, p2));

        if (accumulatedLength + segmentLength >= targetLength) {
            double ratio = (targetLength - accumulatedLength) / segmentLength;
            return {
                p1[0] + ratio * (p2[0] - p1[0]),
                p1[1] + ratio * (p2[1] - p1[1]),
                p1[2] + ratio * (p2[2] - p1[2])
            };
        }
        accumulatedLength += segmentLength;
    }
    return endPoint; // 返回终点
}
// std::vector<double> MainWindow::GeodesicInterpolation(
//     vtkPolyData* mesh,
//     const std::vector<double>& startPoint,
//     const std::vector<double>& endPoint,
//     double t)
// {
//     // 获取测地路径（假设 GetGeodesicPath 已优化）
//     vtkSmartPointer<vtkPolyData> path = GetGeodesicPath(mesh, startPoint.data(), endPoint.data());
//     if (!path || path->GetNumberOfPoints() < 2) {
//         return endPoint; // 路径无效时返回终点
//     }

//     vtkPoints* points = path->GetPoints();
//     const int numPoints = points->GetNumberOfPoints();

//     // 合并总长度计算和累积距离预处理（单次遍历）
//     std::vector<double> cumulativeDistances;
//     cumulativeDistances.reserve(numPoints);
//     cumulativeDistances.push_back(0.0); // 起点累积距离为0

//     double totalLength = 0.0;
//     for (int i = 0; i < numPoints - 1; ++i) {
//         double p1[3], p2[3];
//         points->GetPoint(i, p1);
//         points->GetPoint(i + 1, p2);

//         const double segmentLength = sqrt(vtkMath::Distance2BetweenPoints(p1, p2));
//         totalLength += segmentLength;
//         cumulativeDistances.push_back(totalLength);
//     }

//     // 边界检查（t 应在 [0,1] 范围内）
//     t = std::max(0.0, std::min(1.0, t));
//     const double targetLength = t * totalLength;

//     // 二分查找加速（查找第一个超过 targetLength 的索引）
//     auto it = std::upper_bound(cumulativeDistances.begin(), cumulativeDistances.end(), targetLength);
//     const int segmentIdx = std::distance(cumulativeDistances.begin(), it) - 1;

//     // 获取线段的起点和终点坐标
//     double segmentStart[3], segmentEnd[3];
//     points->GetPoint(segmentIdx, segmentStart);    // 获取起点坐标
//     points->GetPoint(segmentIdx + 1, segmentEnd);  // 获取终点坐标

//     const double segmentLength = sqrt(vtkMath::Distance2BetweenPoints(segmentStart, segmentEnd));
//     if (segmentLength < 1e-6) { // 防止除以零（连续点）
//         return {segmentStart[0], segmentStart[1], segmentStart[2]};
//     }

//     const double ratio = (targetLength - cumulativeDistances[segmentIdx]) / segmentLength;
//     return {
//         segmentStart[0] + ratio * (segmentEnd[0] - segmentStart[0]),
//         segmentStart[1] + ratio * (segmentEnd[1] - segmentStart[1]),
//         segmentStart[2] + ratio * (segmentEnd[2] - segmentStart[2])
//     };
// }


std::vector<double> SurfaceAwareDeCasteljau(
    vtkPolyData* mesh,
    const std::vector<std::vector<double>>& controlPoints,
    double t)
{

    // qDebug() << "drawbezier";
    MainWindow mainwindow;
    if (controlPoints.size() == 1) return controlPoints[0];

    std::vector<std::vector<double>> newLevel;
    for (size_t i = 0; i < controlPoints.size()-1; i++) {
            newLevel.push_back(mainwindow.GeodesicInterpolation(mesh,controlPoints[i],controlPoints[i+1],t));
    }

    return SurfaceAwareDeCasteljau(mesh, newLevel, t);
}


void MainWindow::OnLeftButtonClick(
    vtkObject* caller,
    unsigned long eid,
    void* clientdata,
    void* calldata)
{

    MainWindow* self = static_cast<MainWindow*>(clientdata); // 获取 MainWindow 实例
    if (!self || !self->picker || !self->renderer || !self->stlPolyData){
        qDebug() << "左键点击无效" ;
        return;
    }
    if (!self->isAddControlPointEnabled) {
        return;  // 如果没有启用添加控制点功能，则直接返回
    }
    vtkRenderWindowInteractor* interactor = static_cast<vtkRenderWindowInteractor*>(caller);

    int* clickPos = interactor->GetEventPosition();

    if (self->picker->Pick(clickPos[0], clickPos[1], 0, self->renderer))
    {
        double pickedPosition[3];
        self->picker->GetPickPosition(pickedPosition);
        qDebug() << "点击位置:" << pickedPosition[0] << pickedPosition[1] << pickedPosition[2];

        std::vector<double> point = {pickedPosition[0], pickedPosition[1], pickedPosition[2]};

        // 投影点到表面（可选）
        point = self->PointOntoSurface(point, self->stlPolyData);

        // 添加到控制点并刷新显示
        self->controlPoints.push_back(point);
        self->drawControlpoints(self->controlPoints);
    }
}


void MainWindow::OnRightButtonClick(
    vtkObject* caller,
    unsigned long eid,
    void* clientdata,
    void* calldata)
{
    MainWindow* self = static_cast<MainWindow*>(clientdata);
    if (!self || !self->picker || !self->renderer || !self->stlPolyData){
        qDebug() << "右键点击无效";
        return;
    }

    vtkRenderWindowInteractor* interactor = static_cast<vtkRenderWindowInteractor*>(caller);
    int* clickPos = interactor->GetEventPosition();

    if (self->picker->Pick(clickPos[0], clickPos[1], 0, self->renderer)) {
        double pickedPosition[3];
        self->picker->GetPickPosition(pickedPosition);
        qDebug() << "右键点击位置:" << pickedPosition[0] << pickedPosition[1] << pickedPosition[2];

        // 尝试删除距离 pickedPosition 最近的控制点
        double minDist2 = std::numeric_limits<double>::max();
        int deleteIndex = -1;

        for (int i = 0; i < self->controlPoints.size(); ++i) {
            double dist2 = vtkMath::Distance2BetweenPoints(
                pickedPosition, self->controlPoints[i].data());
            if (dist2 < 5.0) {
                if (dist2 < minDist2) {
                    minDist2 = dist2;
                    deleteIndex = i;
                }
            }
        }

        if (deleteIndex >= 0) {
            self->controlPoints.erase(self->controlPoints.begin() + deleteIndex);
            self->drawControlpoints(self->controlPoints);
            qDebug() << "已删除控制点#" << deleteIndex;
        } else {
            qDebug() << "未找到附近控制点";
        }
    }
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QDoubleValidator* validator = new QDoubleValidator(this);


    ui->lineEdit_x->setValidator(validator);
    ui->lineEdit_y->setValidator(validator);
    ui->lineEdit_z->setValidator(validator);
    renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
    renderer = vtkSmartPointer<vtkRenderer>::New();
    renderWindow->AddRenderer(renderer);
    // 绑定 VTK 渲染窗口到 Qt 界面
    ui->openGLWidget->setRenderWindow(renderWindow);

    // 设置背景颜色
    renderer->SetBackground(0.1, 0.1, 0.1);

    // 启动交互器
    renderWindowInteractor = ui->openGLWidget->renderWindow()->GetInteractor(); 
    renderWindowInteractor->Initialize();
    // renderWindowInteractor->Start();




    //初始化鼠标点击
    picker = vtkSmartPointer<vtkCellPicker>::New();
    picker->SetTolerance(0.005);


    //鼠标左键点击事件
    vtkSmartPointer<vtkCallbackCommand> leftClickCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    leftClickCallback->SetCallback(MainWindow::OnLeftButtonClick);
    leftClickCallback->SetClientData(this);
    renderWindowInteractor->AddObserver(vtkCommand::LeftButtonPressEvent, leftClickCallback);

    //鼠标右键点击事件
    vtkSmartPointer<vtkCallbackCommand> rightClickCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    rightClickCallback->SetCallback(MainWindow::OnRightButtonClick);
    rightClickCallback->SetClientData(this);
    renderWindowInteractor->AddObserver(vtkCommand::RightButtonPressEvent, rightClickCallback);



}


MainWindow::~MainWindow()
{
    delete ui;
}




void MainWindow::drawControlpoints(std::vector<std::vector<double>> controlPoints)
{
    if (!renderer) {
        qDebug() << "Error: Renderer is not initialized!";
        return;
    }

    //初始化 VTK 变量
    if (!controlPointData) {
        controlPointData = vtkSmartPointer<vtkPoints>::New();
        controlPointPolyData = vtkSmartPointer<vtkPolyData>::New();
        controlPointPolyData->SetPoints(controlPointData);

        controlPointGlyphFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New();
        controlPointGlyphFilter->SetInputData(controlPointPolyData);
        controlPointGlyphFilter->Update();

        controlPointMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
        controlPointMapper->SetInputConnection(controlPointGlyphFilter->GetOutputPort());

        controlPointActor = vtkSmartPointer<vtkActor>::New();
        controlPointActor->SetMapper(controlPointMapper);
        controlPointActor->GetProperty()->SetColor(0, 1, 0);  // 绿色控制点
        controlPointActor->GetProperty()->SetPointSize(8);

        // 把控制点 Actor 添加到渲染器
        renderer->AddActor(controlPointActor);
    }

    controlPointData->Initialize();
    controlPointPolyData->Initialize();

    // 添加所有新控制点
    for (const auto& p : controlPoints) {
        controlPointData->InsertNextPoint(p[0], p[1], p[2]);
    }

    // 通知 VTK 数据已更新
    controlPointPolyData->SetPoints(controlPointData); // 重新设置点数据
    controlPointPolyData->Modified();
    controlPointGlyphFilter->Update();
    controlPointMapper->Update();

    // 确保渲染器已更新
    renderWindow->Render();


}



void MainWindow::drawBezier(
    vtkPolyData* mesh,
    const std::vector<std::vector<double>>& controlPoints)
{
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    vtkSmartPointer<vtkPolyLine> line = vtkSmartPointer<vtkPolyLine>::New();

    // 生成100个测地插值点
    int resolution = 100;
    // qDebug() << "drawbezier";
    line->GetPointIds()->SetNumberOfIds(resolution);
    for (int i = 0; i < resolution; i++) {
        double t = static_cast<double>(i) / (resolution-1);
        auto point = SurfaceAwareDeCasteljau(mesh, controlPoints, t);
        points->InsertNextPoint(point.data());
        line->GetPointIds()->SetId(i, i);
    }

    // 创建并显示曲线
    vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
    lines->InsertNextCell(line);

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->SetPoints(points);
    polyData->SetLines(lines);

    // 更新或创建Actor
    if (!bezierActor) {
        bezierActor = vtkSmartPointer<vtkActor>::New();
        bezierActor->GetProperty()->SetColor(1, 0, 0);
        bezierActor->GetProperty()->SetLineWidth(3);
        bezierActor->GetProperty()->SetOpacity(1.0);
        renderer->AddActor(bezierActor);
    }

    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData(polyData);
    bezierActor->SetMapper(mapper);

    renderWindow->Render();
}




void MainWindow::loadSTLFile() {


    QString defaultDir = "D:/Surface_Mesh";
    QString fileName = QFileDialog::getOpenFileName(this, "打开STL文件", defaultDir, "STL Files (*.stl)");

    // 读取 STL 文件
    vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
    reader->SetFileName(fileName.toStdString().c_str());
    reader->Update();
    stlPolyData = reader->GetOutput(); //

    vtkSmartPointer<vtkPolyData> polyData = reader->GetOutput();
    if (!polyData) {
        QMessageBox::warning(this, "错误", "无法加载STL文件");
        return;
    }

    // 创建映射器和演员
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData(polyData);
    //初始化或重置actor（STL模型对象）
    STLmodelActor = vtkSmartPointer<vtkActor>::New();
    STLmodelActor->SetMapper(mapper);

    // 添加模型到渲染器
    renderer->RemoveAllViewProps();
    renderer->AddActor(STLmodelActor);
    renderWindow->Render();
    renderer->ResetCamera();

    // 计算黎曼质心
    // std::vector<double> centroid = computeRiemannianCentroid(polyData);
    // qDebug() << "黎曼质心" << centroid[0] << centroid[1] << centroid[2];
}

// std::vector<double> MainWindow::computeRiemannianCentroid(vtkSmartPointer<vtkPolyData> polyData) {
//     if (!polyData || polyData->GetNumberOfCells() == 0) {
//         qDebug() << "错误STL数据无效无法计算黎曼质心";
//         return {0.0, 0.0, 0.0};
//     }

//     double totalArea = 0.0;
//     std::vector<double> centroid = {0.0, 0.0, 0.0};

//     // 遍每个三角形单元
//     for (vtkIdType i = 0; i < polyData->GetNumberOfCells(); i++) {
//         vtkCell* cell = polyData->GetCell(i);
//         if (cell->GetNumberOfPoints() != 3) continue;  // 仅处理三角形

//         // 三角形顶点坐标
//         double p0[3], p1[3], p2[3];
//         polyData->GetPoint(cell->GetPointId(0), p0);
//         polyData->GetPoint(cell->GetPointId(1), p1);
//         polyData->GetPoint(cell->GetPointId(2), p2);

//         // 三角形重心
//         double triCentroid[3] = {
//             (p0[0] + p1[0] + p2[0]) / 3.0,
//             (p0[1] + p1[1] + p2[1]) / 3.0,
//             (p0[2] + p1[2] + p2[2]) / 3.0
//         };

//         // 三角形面积
//         double v1[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]};
//         double v2[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]};
//         double crossProduct[3] = {
//             v1[1] * v2[2] - v1[2] * v2[1],
//             v1[2] * v2[0] - v1[0] * v2[2],
//             v1[0] * v2[1] - v1[1] * v2[0]
//         };
//         double area = 0.5 * sqrt(crossProduct[0] * crossProduct[0] +
//                                  crossProduct[1] * crossProduct[1] +
//                                  crossProduct[2] * crossProduct[2]);

//         // 加权质心
//         totalArea += area;
//         centroid[0] += triCentroid[0] * area;
//         centroid[1] += triCentroid[1] * area;
//         centroid[2] += triCentroid[2] * area;
//     }

//     if (totalArea > 0) {
//         centroid[0] /= totalArea;
//         centroid[1] /= totalArea;
//         centroid[2] /= totalArea;
//     }

//     return centroid;
// }


void MainWindow::on_pushButton_addPointpushButton_addPoint_clicked()
{
    isAddControlPointEnabled = !isAddControlPointEnabled;  // 切换状态
    QString status = isAddControlPointEnabled ? "on" : "off";
    QMessageBox::information(this, "change", "add" + status);
}


void MainWindow::on_pushButton_drawBezier_clicked()
{
    //drawBezier(controlPoints);
    drawBezier(stlPolyData, controlPoints);

}


void MainWindow::on_pushButton_loadfile_clicked()
{
    loadSTLFile();
}




void MainWindow::on_pushButton_translucent_clicked()
{
    isTranslucentEnabled = !isTranslucentEnabled;
    QString status = isAddControlPointEnabled ? "off" : "on";
    if(isTranslucentEnabled){
        STLmodelActor->GetProperty()->SetOpacity(0.5);
    }
    else{
        STLmodelActor->GetProperty()->SetOpacity(1.0);
    }
    QMessageBox::information(this, "change", "translucent" + status);
    renderWindow->Render();

}


void MainWindow::on_pushButton_deleteControlpoints_clicked()
{

    // controlPoints.erase(controlPoints.begin() + i);

}


void MainWindow::on_pushButton_resetSTLmodel_clicked()
{
    controlPoints.clear();
    drawControlpoints(controlPoints);  // 刷新控制点显示

    // 清空渲染器中的所有内容
    renderer->RemoveAllViewProps();

    // 刷新渲染窗口
    renderWindow->Render();

    qDebug() << "reset_over";
}

